<!--下拉选择组件-->
<template>
  <a-form-item :label="label">
    <a-select
        dropdownClassName="c-form-select-dropdown"
        option-filter-prop="children"
        v-decorator="vDecorator"
        :style="getStyle"
        :mode="mode"
        :placeholder="!isDisabled?cplaceholder:''"
        :disabled="isDisabled"
        :allowClear="allowClear"
        :filter-option="filterOption"
        :showSearch="showSearch"
        :maxTagCount="0"
        :maxTagPlaceholder="maxTagPlaceholder"
        :dropdownMatchSelectWidth="selectWidth"
        :selectData="selectData"
        @select="select"
        @search="search"
        @change="change"
        @popupScroll="(e)=>selectEditorScroll(e)"
    >
      <div slot="dropdownRender" slot-scope="menu">
        <v-nodes :vnodes="menu"/>
        <template v-if="addChildrenFlag">
          <a-divider style="margin: 4px 0;"/>
          <div
              style="padding: 4px 8px 8px 8px; cursor: pointer;"
              @mousedown="e => e.preventDefault()"
              @click="addItem"
          >
            <a-icon type="plus"/>
            <span title="添加项只作用于当前页面，临时选项数据">添加项（输入框内容）</span>
          </div>
        </template>
      </div>
      <a-select-option
          v-for="(record,index) in getSelectEditorOptions()"
          :key="index.toString()"
          :value="record.value"
          :disabled="disabledData.includes(record.value)"
          :title="record.text"
      >{{ record.text }}
      </a-select-option>
    </a-select>
  </a-form-item>
</template>

<script>
import './css/form.less'
import { mixin } from './js/form.js'

export default {
  name: 'AntFormSelect',
  mixins: [mixin],
  components: {
    VNodes: {
      functional: true,
      render: (h, ctx) => ctx.props.vnodes
    }
  },
  props: {
    /**
     * 是否禁用
     */
    disabled: {
      type: Boolean,
      default: false
    },
    /**
     * 是否由form表单自动布局
     */
    autoLayoutByForm: {
      type: Boolean,
      default: true
    },
    /**
     * 显示文本
     */
    label: {
      type: String,
      default: ''
    },
    /**
     * 输入提示
     */
    placeholder: {
      type: String,
      default: ''
    },
    /**
     * 下拉数据源，接口url或数组
     */
    selectData: {
      type: [Array, String],
      default: () => []
    },
    /**
     * 绑定字段 ['phone' ,{ rules: [{ required: true},{validator:function(rule, value, callback)] }],自定义验证方法时callback回调函数必须在方法中调用，
     * 失败返回错误提示callback("xxx")，成功返回callback()
     * 字段值多个逗号隔开
     */
    vDecorator: {
      type: Array,
      default: () => []
    },
    /**
     * 下拉菜单和选择器是否同宽
     */
    selectWidth: {
      type: Boolean,
      default: true
    },
    /**
     * default单选或multiple多选
     */
    mode: {
      type: String,
      default: 'default'
    },
    /**
     * 是否允许清除选择
     */
    allowClear: {
      type: Boolean,
      default: true
    },
    /**
     * 是否显示搜索框
     */
    showSearch: {
      type: Boolean,
      default: true
    },
    /**
     * 禁用的下拉选择项
     */
    disabledData: {
      type: [Array, String],
      default() {
        return []
      }
    },
    /**
     * 是否可手动添加下拉子项，仅用于text = value时，且当前页面生效，不会改变数据源
     */
    addChildrenFlag: {
      type: Boolean,
      default: false
    },
    /**
     * 下拉数据显示值
     */
    dataTitle: {
      type: String,
      default: 'text'
    },
    /**
     * 下拉数据存储值
     */
    dataValue: {
      type: String,
      default: 'value'
    },
    /**
     * css样式，优先级最高
     */
    cstyle: {
      type: String,
      default: ''
    },
    /**
     * 非自动布局的宽度，优先级最低
     */
    defaultWidth: {
      type: Number,
      default: 240
    }
  },
  data() {
    return {
      //是否禁用和输入提示，由AntForm组件调用
      cdisabled: false,
      cplaceholder: this.placeholder ? this.placeholder : '请选择' + this.label,
      // 所有数据存
      dataSource: [],
      selectValue: [],
      // 上次选择记录
      lastKey: null,
      // 查询信息
      searchValue: '',
      // 当前下拉页加载次数
      selectDropdownLoadMore: 1,
      // 下拉编辑器单次渲染数据数
      selectEditorLoadLimitNum: 20
    }
  },
  computed: {
    /**
     * 获取样式
     */
    getStyle() {
      return { width: (this.percentageLayoutWidth ? this.percentageLayoutWidth : this.defaultWidth) + 'px', ...this.cstyle }
    }
  },
  created() {
  },
  mounted() {
    this.loadData(this.selectData)
    // 自动添加验证为空时的message
    let vDecorator = this.vDecorator
    if (vDecorator.length > 1 && vDecorator[1].rules) {
      let rules = vDecorator[1].rules
      rules.forEach(obj => {
        if (obj.required && !obj.message) {
          obj.message = '请选择' + this.label
        }
      })
    }
  },
  watch: {
    selectData(val) {
      this.loadData(val)
    }
  },
  beforeDestroy() {
  },
  methods: {
    /**
     * 选择下拉数据触发事件
     * @param value
     * @param option
     */
    select(value, option) {
      const data = this.getSelectEditorOptions().find(el => el.value === value)
      this.$emit('select', value, data)
    },
    /**
     * 加载数据源
     * @param val
     */
    loadData(val) {
      if (val instanceof Array) {
        this.dataSource = val
      } else {
        this.$getAction(val, {}).then(res => {
          this.dataSource = res.data
        })
      }
      //当返回字段值与本组件不同时，进行兼容
      if (this.dataTitle !== 'text' || this.dataValue !== 'value') {
        this.dataSource.forEach(item => {
          item.text = item[this.dataTitle]
          item.value = item[this.dataValue]
        })
      }
    },
    /**
     * 选择内容改变事件
     * @param value
     * @param option
     */
    change(value, option) {
      this.lastKey = this.selectValue
      this.$nextTick(() => {
        this.selectValue = value
        this.searchValue = '' // 查询条件区域置空
        const data = this.getSelectEditorOptions().find(el => el.value === value)
        if (value) {
          this.$emit('change', value, option, data)
        } else {
          this.$emit('change', value, option, null)
        }
      })
    },
    // 选择框返回上一次选择数据，返回成功后，上次依据记录为空=》（注：是从新选择上一次数据，但不触发任何事件）
    rollBack() {
      const c = this.getParentForm(this.$parent)
      this.selectValue = this.lastKey
      c.setFieldsValue({ [this.vDecorator[0]]: this.lastKey })
    },
    /**
     * 获取父级form
     */
    getParentForm(param) {
      if (param.$refs.aform) {
        return param.$refs.aform.form
      } else {
        return this.getParentForm(param.$parent)
      }
    },
    /**
     * 触发搜索事件
     * @param value
     */
    search(value) {
      this.searchValue = value
      this.$nextTick(() => {
        this.$emit('search', value)
      })
    },
    /**
     *  是否根据输入项进行筛选。当其为一个函数时，会接收 inputValue option 两个参数，当 option 符合筛选条件时，应返回 true，反之则返回 false。
     * @param input
     * @param option
     * @returns {boolean}
     */
    filterOption(input, option) {
      return true
    },
    /**
     * 赋值之前的转换操作,由AntForm组件自动调用
     * 参数：recordPara，转换之前的record
     * 返回值：转换之后的可用于赋值的对象
     */
    beforeSetValue(recordPara) {
      let record = {}
      let key = this.vDecorator[0]
      let val = recordPara[key]
      if (this.mode !== 'default') {
        if (val) {
          val = val.split(',')
        } else {
          val = []
        }
      }
      record[key] = val
      this.selectValue = val
      return record
    },
    /**
     * 取值之前的转换操作,由AntForm组件自动调用
     * 参数：recordPara，转换之前的record
     * 返回值：转换之后的对象
     */
    beforeGetValue(recordPara) {
      let record = {}
      let key = this.vDecorator[0]
      let val = recordPara[key]
      if (val && this.mode !== 'default') {
        val = val.join(',')
      }
      record[key] = val
      return record
    },
    /**
     * 隐藏 tag 时显示的内容
     * @returns {*}
     */
    maxTagPlaceholder() {
      if (this.mode !== 'default') {
        let data = []
        for (let i = 0; i < this.selectValue.length; i++) {
          let val = this.selectValue[i]
          for (let j = 0; j < this.dataSource.length; j++) {
            if (val === this.dataSource[j].value) {
              data.push(this.dataSource[j].text)
            }
          }
        }
        return <span title={data.join(',')}>{data.join(',')}</span>
      }
    },
    /**
     * 获取下拉编辑器加载得数据
     * @returns {*[]}
     */
    getSelectEditorOptions() {
      let dataSource = this.dataSource
      const limitNum = this.selectDropdownLoadMore * this.selectEditorLoadLimitNum
      if (this.searchValue) {
        dataSource = dataSource.filter(el => el.text && el.text.indexOf(this.searchValue) > -1)
      }
      let arr = dataSource.filter((el, index) => index < limitNum)
      if (this.selectValue && this.selectValue.length > 0) {
        const values = this.mode === 'default' ? [this.selectValue] : this.selectValue
        const selectDatas = dataSource.filter(el => values.find(item => item === el.value))
        if (selectDatas.length > 0) {
          const addData = selectDatas.filter(el => !arr.find(item => item.value === el.value))
          if (addData.length > 0) {
            arr = [...arr, ...addData]
          }
        }
      }
      // 自动选择唯一数据项
      if (this.autoSoloSelection && arr.length === 1) {
        const c = this.getParentForm(this.$parent)
        c.setFieldsValue({ [this.vDecorator[0]]: arr[0].value })
      }
      return arr
    },
    /**
     * 滚动条滚动-动态加载数据
     * @param e
     */
    selectEditorScroll(e) {
      // 内容区域总高度
      const totalHeight =
          e.srcElement.firstChild.clientHeight * this.selectDropdownLoadMore * this.selectEditorLoadLimitNum
      // 内容区域可是高度
      const relativeHeight = e.srcElement.clientHeight
      // 滚动条 滚动距离
      const scrollTop = e.srcElement.scrollTop
      // 当滚动条滚动到底部距离 < 100 时，并且当前可视数据小于总数据时，动态加载可视数据
      if (
          totalHeight - scrollTop - relativeHeight < 100 &&
          this.selectDropdownLoadMore * this.selectEditorLoadLimitNum < this.dataSource.length
      ) {
        this.selectDropdownLoadMore++
        this.$forceUpdate()
      }
    },
    /**
     * 添加临时选项
     */
    addItem() {
      const value = this.searchValue.trim()
      if (!this.searchValue || value === '') {
        this.$message.warning('请输入需要添加的临时下拉数据！')
      } else {
        const obj = this.dataSource.find(el => el.value === value)
        if (obj) {
          this.$message.warning('下拉数据存在，请勿重复添加！')
        } else {
          // 添加数据
          this.dataSource.push({ text: value, value: value })
        }
      }
    }
  }
}
</script>

<style lang="less" scoped>
::v-deep .ant-select-selection.ant-select-selection--multiple {
  height: 33px !important;
  //overflow: auto !important;
}

::v-deep .ant-form-item-control {
  width: 95%;
}

::v-deep .ant-select-search--inline {
  position: absolute !important;
  // display: inline !important;
}

.show-pagination {
  float: right;
  padding: 0 5px 5px 5px;
}

::v-deep .ant-select-selection:hover,
::v-deep .ant-select-open .ant-select-selection {
  border-color: #1a67f8 !important;
}
</style>
